<template>
	<view>
		<view class="tips color_fff size_12 align_c" :class="{ show: ajax.loading }" @tap="getHistoryMsg">
			{{ ajax.loadText }}
		</view>
		<view class="box-1" id="list-box">
			<view class="talk-list">
				<view v-for="(item, index) in talkList" :key="index" :id="`msg-${item.id}`">
					<view class="item flex_col" :class="item.type === 1 ? 'push' : 'pull'">
						<image :src="'http://gpt.szyirxx.com'+item.pic" mode="aspectFill" class="pic"></image>
						<view class="content" v-if="item.type == 1">{{ item.content }}</view>
						<jp-typewriter class="content" v-else :text="item.content" :speed="speed"></jp-typewriter>
					</view>
				</view>
			</view>
		</view>
		<view class="box-2">
			<view class="flex_col">
				<view class="flex_grow">
					<input type="text" class="content" @confirm="send" v-model="content" placeholder="请输入聊天内容"
						placeholder-style="color:#DDD;" :cursor-spacing="6" />
				</view>
				<!-- <view class="send" @tap="send"></view> -->
				<button class="send" @tap="send">发送</button>
			</view>
		</view>
	</view>
</template>

<script>
	function getCookie(name) {
		var cookies = document.cookie.split(';');
		for (var i = 0; i < cookies.length; i++) {
			var cookie = cookies[i].trim();
			if (cookie.indexOf(name + '=') === 0) {
				return cookie.substring(name.length + 1, cookie.length);
			}
		}
		return null;
	}
	let contextarray = []
	export default {
		data() {
			return {
				talkList: [],
				speed: 50, // 打字速度，单位：毫秒
				ajax: {
					rows: 20,
					page: 1,
					flag: true,
					loading: false,
					loadText: '正在获取消息',
				},
				content: '',
				aiContent: '',
				getContent: false,
				userinfo:{}
			};
		},
		beforeDestroy() {
			// 在组件销毁前关闭 EventSource 连接
			if (this.eventSource) {
				this.eventSource.close();
			}
		},
		onLoad() {
			this.postinfo()
		},
		methods: {
			postinfo(){
				this.$Request({
					method: 'POST',
					url: '/user/getUserInfo'
				}).then(res => {
					if (res.data.code == 1) {
						this.userinfo = res.data.data
						let replyMessage = {
							id: new Date().getTime(),
							content: '你好,需要帮助吗！',
							type: 0,
							pic:this.userinfo.ai_avatar,
						};
						this.talkList.push(replyMessage);
					}
				})
			},
			setupEventSource() {
				this.eventSource = new EventSource("/main/stream.php");
				// 监听服务器端发送的消息
				this.eventSource.addEventListener('message', (event) => {
					if (this.getContent && event.data == "[DONE]") {
						this.getContent = false
						let replyMessage = {
							id: new Date().getTime(),
							content: this.aiContent,
							type: 0,
							pic:this.userinfo.ai_avatar,
						};
						contextarray.at(-1).push(this.aiContent)
						contextarray = contextarray.slice(-5);
						this.aiContent = ''
						this.ajax.loading = false;
						this.ajax.loadText = '消息获取成功';
						this.talkList.push(replyMessage);
						this.eventSource.close();
						// 处理接收到的消息
						this.$nextTick(() => {
							uni.pageScrollTo({
								scrollTop: 999999,
								duration: 0,
							});
						});
					} else {
						const data = JSON.parse(event.data)
						if (!this.getContent) return
						var json = data
						if (json.choices[0].delta.hasOwnProperty("content")) {
							if (this.aiContent == "") {
								this.aiContent = json.choices[0].delta.content.replace(/^\n+/,
									''); //去掉回复消息中偶尔开头就存在的连续换行符
							} else {
								this.aiContent += json.choices[0].delta.content;
							}
						}
					}
					// console.log("?? ~ file: index.vue:146 ~ setupEventSource ~ this.aiContent:", this.aiContent)
				});

				// 监听 SSE 的错误
				this.eventSource.addEventListener('error', (error) => {
					var errcode = getCookie("errcode");
					switch (errcode) {
						case "invalid_api_key":
							console.log("API-KEY不合法");
							break;
						case "context_length_exceeded":
							console.log("问题和上下文长度超限，请重新提问");
							break;
						case "rate_limit_reached":
							console.log("同时访问用户过多，请稍后再试");
							break;
						case "access_terminated":
							console.log("违规使用，API-KEY被封禁");
							break;
						case "no_api_key":
							console.log("未提供API-KEY");
							break;
						case "insufficient_quota":
							console.log("API-KEY余额不足");
							break;
						case "account_deactivated":
							console.log("账户已禁用");
							break;
						case "model_overloaded":
							console.log("OpenAI模型超负荷，请重新发起请求");
							break;
						case null:
							console.log("OpenAI服务器访问超时或未知类型错误");
							break;
						default:
							console.log("OpenAI服务器故障，错误类型：" + errcode);
					}
					console.error('EventSource failed:', error);
				});
			},

			async getHistoryMsg() {
				if (!this.ajax.flag) {
					return;
				}

				this.hideLoadTips();
				this.ajax.flag = false;
				let data = await this.joinHistoryMsg();

				console.log('----- 模拟数据格式，供参考 -----');
				console.log(data);

				let selector = '';

				if (this.ajax.page > 1) {
					selector = `#msg-${this.talkList[0].id}`;
				} else {
					selector = `#msg-${data[data.length - 1].id}`;
				}

				this.talkList = [...data, ...this.talkList];

				this.$nextTick(() => {
					this.setPageScrollTo(selector);
					this.hideLoadTips(true);

					if (data.length < this.ajax.rows) {
						// 可在此处编写无更多消息数据时的逻辑
					} else {
						this.ajax.page++;
						setTimeout(() => {
							this.ajax.flag = true;
						}, 200);
					}
				});
			},
			joinHistoryMsg() {
				let join = () => {
					let arr = [];
					let startIndex = (this.ajax.page - 1) * this.ajax.rows;
					let endIndex = startIndex + this.ajax.rows;
					for (let i = startIndex; i < endIndex; i++) {
						arr.push({
							id: i,
							content: `这是历史记录的第${i + 1}条消息`,
							type: Math.random() > 0.5 ? 1 : 0,
							pic: '/static/logo.png',
						});
					}
					arr.reverse();
					return arr;
				};

				return new Promise((done, fail) => {
					setTimeout(() => {
						let data = join();
						done(data);
					}, 1500);
				});
			},
			setPageScrollTo(selector) {
				let view = uni.createSelectorQuery().in(this).select(selector);
				view.boundingClientRect((res) => {
					uni.pageScrollTo({
						scrollTop: res.top - 30,
						duration: 0,
					});
				}).exec();
			},
			hideLoadTips(flag) {
				if (flag) {
					this.ajax.loadText = '消息获取成功';
					setTimeout(() => {
						this.ajax.loading = false;
					}, 300);
				} else {
					this.ajax.loading = true;
					this.ajax.loadText = '正在获取消息';
				}
			},
			async send() {
				if (!this.content) {
					uni.showToast({
						title: '请输入有效的内容',
						icon: 'none',
					});
					return;
				}

				// 显示加载状态
				this.ajax.loading = true;
				this.ajax.loadText = '正在发送';

				let token = uni.getStorageSync("token") || ''
				// 模拟网络请求的延时
				const res = await uni.request({
					method: 'POST',
					url: '/main/setsession.php',
					data: {
						message: this.content,
						context: contextarray.length ? JSON.stringify(contextarray) : '[]',
						type: 1
					},
					header: {
						Token: token,
						'Content-Type': 'application/x-www-form-urlencoded',
						lang: 'en-us',
					}
				})
				if (!res.data.success) {
					return
				}

				// 隐藏加载状态
				this.ajax.loading = false;
				this.ajax.loadText = '消息获取成功';

				// 将当前发送信息添加到消息列表
				let sentMessage = {
					id: new Date().getTime(),
					content: this.content,
					type: 1,
					pic: this.userinfo.avatar,
				};
				this.talkList.push(sentMessage);
				this.getContent = true
				this.ajax.loading = true;
				this.ajax.loadText = '获取消息中';
				contextarray.push([this.content])
				this.setupEventSource()
				this.$nextTick(() => {
					this.content = '';
					uni.pageScrollTo({
						scrollTop: 999999,
						duration: 0,
					});
				});
			},

			async simulateNetworkRequest() {
				// 模拟网络请求的异步操作
				return new Promise((resolve) => {
					setTimeout(() => {
						resolve();
					}, 1000);
				});
			},
		},
	};
</script>

<style lang="scss">
	@import "@/lib/global.scss";

	.contentImage {
		width: 200rpx;

	}

	page {
		background-color: #F3F3F3;
		font-size: 28rpx;
	}

	/* 加载数据提示 */
	.tips {
		position: fixed;
		left: 0;
		top: var(--window-top);
		width: 100%;
		z-index: 9;
		background-color: rgba(0, 0, 0, 0.15);
		height: 72rpx;
		line-height: 72rpx;
		transform: translateY(-80rpx);
		transition: transform 0.3s ease-in-out 0s;

		&.show {
			transform: translateY(0);
		}
	}

	.box-1 {
		width: 100%;
		height: auto;
		padding-bottom: 100rpx;
		box-sizing: content-box;

		/* 兼容iPhoneX */
		margin-bottom: 0;
		margin-bottom: constant(safe-area-inset-bottom);
		margin-bottom: env(safe-area-inset-bottom);
	}

	.box-2 {
		position: fixed;
		left: 0;
		width: 100%;
		bottom: 0;
		height: auto;
		z-index: 2;
		border-top: #e5e5e5 solid 1px;
		box-sizing: content-box;
		background-color: #F3F3F3;

		/* 兼容iPhoneX */
		padding-bottom: 0;
		padding-bottom: constant(safe-area-inset-bottom);
		padding-bottom: env(safe-area-inset-bottom);

		>view {
			padding: 0 20rpx;
			height: 100rpx;
		}

		.content {
			background-color: #fff;
			height: 64rpx;
			padding: 0 20rpx;
			border-radius: 32rpx;
			font-size: 28rpx;

		}

		.send {
			background-color: #42b983;
			color: #fff;
			height: 64rpx;
			margin-left: 20rpx;
			border-radius: 32rpx;
			padding: 0;
			width: 120rpx;
			line-height: 62rpx;

			&:active {
				background-color: #5fc496;
			}
		}
	}

	.talk-list {
		padding-bottom: 20rpx;

		/* 消息项，基础类 */
		.item {
			padding: 20rpx 20rpx 0 20rpx;
			align-items: flex-start;
			align-content: flex-start;
			color: #333;

			.pic {
				width: 92rpx;
				height: 92rpx;
				border-radius: 50%;
				border: #fff solid 1px;
			}

			.content {
				padding: 20rpx;
				border-radius: 4px;
				max-width: 500rpx;
				word-break: break-all;
				line-height: 52rpx;
				position: relative;
			}

			/* 收到的消息 */
			&.pull {
				.content {
					margin-left: 32rpx;
					background-color: #fff;

					&::after {
						content: '';
						display: block;
						width: 0;
						height: 0;
						border-top: 16rpx solid transparent;
						border-bottom: 16rpx solid transparent;
						border-right: 20rpx solid #fff;
						position: absolute;
						top: 30rpx;
						left: -18rpx;
					}
				}
			}

			/* 发出的消息 */
			&.push {
				/* 主轴为水平方向，起点在右端。使不修改DOM结构，也能改变元素排列顺序 */
				flex-direction: row-reverse;

				.content {
					margin-right: 32rpx;
					background-color: #a0e959;

					&::after {
						content: '';
						display: block;
						width: 0;
						height: 0;
						border-top: 16rpx solid transparent;
						border-bottom: 16rpx solid transparent;
						border-left: 20rpx solid #a0e959;
						position: absolute;
						top: 30rpx;
						right: -18rpx;
					}
				}
			}
		}
	}
</style>